博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
项目总结 20171226
阅读量:6259 次
发布时间:2019-06-22

本文共 5826 字,大约阅读时间需要 19 分钟。

clipboard.png

1. 借助require.context预加载图片

项目中为了确保页面显示时,图片已经全部加载完毕,因此需要提前加载图片,加载图片的过程使用进度条显示。

在webpack构建的项目中,可以使用require.context来获取到静态资源的地址。语法如下:

require.context(directory, useSubdirectories = false, regExp = /^\.\//)

第一个参数表示要搜索的文件夹目录,该目录支持相对路径与在配置文件中定义的路径别名。

第二个参数表示是否搜索其子目录。
第三个参数是一个用来匹配文件的正则表达式。

require.context('modules/App', true, /\.(png|jpg|jpeg|gif)$/);// 创建一个包含App目录下所有图片的上下文模块

可以使用该上下文模块自带的keys方法得到路径组成的数组。

const images = require.context('modules/App/', true, /\.(png|jpeg|jpg|gif)$/);console.log(images.keys());

效果大概如下图所示。

clipboard.png

得到图片路径之后,就可以借助Promise.all来完成图片预加载,确保图片加载完成之后再渲染页面。

Promise.all(images.keys().map(path => {  const image = new Image();  image.src = path;  image.onload = image.onerror = () => {    resolve();  }}))

但是在开发中遇到一个问题,本地页面引用的图片是编译过后的图片地址,并不是相对路径,因此如果直接这样的话会因此地址不一致而报错。

clipboard.png

解决办法是在设置image对象src属性时,修改如下:

image.src = images(path);// images 是由require.context 创建的上下文模块

打印出images(path)之后的图片路径如下:

clipboard.png

上面的修复方式可以使用如下的知识点来理解。

const ctx = require.context('modules/App', true, /*\.js/);const table = ctx('./table.js');// 上面的代码等价于const table = require('modules/App/table.js'); // 使用require引入模块

当还需要从服务端提前加载其他资源时,可以使用数组的concat方法一起放入Promise.all中。

Promise.all(images.keys().map(  // ...).concat(http.get('/api/v1/summary')))

2. 细节优化

整个页面的显示,一共有15页构成,由于每一页的逻辑与效果都有不少差异,因此将每一页定义为了一个组件,最初在引入这些模块时很糟糕的这样做:

import Page00 from './Page00';import Page01 from './Page01';import Page02 from './Page02';import Page03 from './Page03';import Page04 from './Page04';import Page05 from './Page05';import Page06 from './Page06';import Page07 from './Page07';import Page08 from './Page08';import Page09 from './Page09';import Page10 from './Page10';import Page11 from './Page11';import Page12 from './Page12';import Page13 from './Page13';import Page14 from './Page14';// render里也很复杂// ...render() {  return (      
...
)}

当组件更多时,这样的引入方式自然是不合理的,可以使用循环的方式来引入代码,优化如下:

const allPages = [];for(let i = 0; i < 15; i++) {  const id = `0${i}`.slice(-2);  allPages.push(require(`./Page${id}`).default)}

这样就将所有的Page组件放在了allPages数组中。

render里也可以使用map来渲染。

render() {  return (    
{allPages.map(({ id, Component: Page }) =>
)}
)}

3. 使用高阶组件处理公共逻辑

每一个Page组件中,都有共同的元素或逻辑,包括logo,分享当前屏幕截图按钮,统计逻辑,判断对应页面是否显示等。可以将这些共用逻辑使用高阶组件来处理以简化代码。

因此定义了withBox组件来处理它们。

import React from 'react';import logo from './images/logo.png';import { sendEvent } from 'utils/track';import share from './share';export default function(Wrapped, checkProp) {  return class NewPage extends React.Component {    shareScreen = () => {      const id = this.refs.box.getAttribute('data-page-id');      this.refs.box.classList.add('will-screenshot');      setTimeout(() => share.shareScreenshot(), 100);      setTimeout(() => this.refs.box.classList.remove('will-screenshot'), 1500);      sendEvent('share-click', 'page' + id);      sendEvent('click', 'share-btn');    };    render() {      const { id, className, ...props } = this.props;      const cls = className ? `page${id} ${className}` : `page${id}`;      if (!checkProp || (props.info[checkProp] !== null && props.info[checkProp] !== 'undefined')) {        return (          
tigerbrokers
); } return null; } };}

4. 通过添加/删除元素的方式统一控制动画

首先定义一个class如下,将会参与动画的元素(或其父级)都添加该class以隐藏。

.aninode {  visibility: hidden;}

并在同元素(或父级)添加了animated时,元素显示。

.animated {  &.aninode, .aninode {    visibility: visible;  }}

并在运动元素的class中添加了animated时,运动生效,因此定义运动css时,应该这样做:

.animated {  &.flyTopIn, .flyTopIn {    animation-name: flyTopIn;    animation-duration: 1s;  }  /* more */}

因此,运动元素在运动开始之前,应该保持这样

需要运动时,在该元素的class中添加animated即可。

// or

使用sass的循环语法定义delay样式

@for $i from 0 through $delay_count {  .animated .delay#{$i * 100} {    animation-delay: $i * 100;    animation-fill-mode: backwards;  }}

5. 小数精度问题导致的bug

js的计算中,经常会遇到小数精度的问题,最初没有注意,导致数据显示出了很多问题。例如如下计算结果

1.099 * 100109.89999999999999

解决方法如下:

(1.099 * 100).toFixed(2)

clipboard.png

6. Promise与setTimeout的写法问题

利用setTimeout判断某个对象是否注入成功。

// 错误写法export const checkSDK = () => {    var timer = null;    const start = Date.now();    return new Promise((resolve, reject) => {        if (typeof window.TigerBridge === 'object') {            resolve();            return;        }        if (Date.now() - start <= 5 * 1000) {            clearTimeout(timer);            timer = setTimeout(checkSDK, 100);            return;        }        reject();    })}// 正确写法export const checkBridge = () => {    var timer = null;    const start = Date.now();    function check(resolve, reject) {        if (typeof window.TigerBridge === 'object') {            resolve();            return true;        }         if (Date.now() - start <= 5 * 1000) {            clearTimeout(timer);            timer = setTimeout(check.bind(null, resolve, reject), 100);            return;        }        reject();        return false;    }    return new Promise((resolve, reject) => check(resolve, reject))}

本地模拟注入过程

if (process.env.NODE_ENV != 'production') {    setTimeout(() => {        window.TigerBridge = {            getAccessToken: () => {                return pkg.token;            },            isAccountPermissionLimited: () => false        };    }, 1600);}

7. 图片串行加载优化

一次性加载所有图片会导致浏览器http线程阻塞严重。因此需要稍作优化,让图片一张一张加载。

// 优化前images.keys().map(path => new Promise(resolve => {  const image = new Image();  image.src = images(path);  image.onload = image.onerror = resolve;}))// 优化后images.keys().reduce((cachePromise, path) => cachePromise.then(() => {  return new Promise(resolve => {    const image = new Image();    const complete = () => {      clearTimeout(timer);      resolve();    }    const timer = setTimeout(complete, 1000);  // 单张图片最多加载1s    image.src = images(path);    image.onload = image.onerror = complete;  })}), Promise.resolve());

转载地址:http://oqnsa.baihongyu.com/

你可能感兴趣的文章
Selenium 自动登录考勤系统
查看>>
关于如何以编程的方式执行TestNG
查看>>
智能照明造福千家万户 家居智能不再是梦
查看>>
物联网如何跳出“看起来很美”?
查看>>
浅谈MySQL 数据库性能优化
查看>>
《UNIX/Linux 系统管理技术手册(第四版)》——1.10 其他的权威文档
查看>>
灵动空间 创享生活
查看>>
《UNIX网络编程 卷1:套接字联网API(第3版)》——8.6 UDP回射客户程序:dg_cli函数...
查看>>
不要将时间浪费到编写完美代码上
查看>>
《第一桶金怎么赚——淘宝开店创业致富一册通》一一第1章 创业梦想,怎样起步...
查看>>
基于容器服务的持续集成与云端交付(三)- 从零搭建持续交付系统
查看>>
《算法基础:打开算法之门》一3.4 归并排序
查看>>
高德开放平台开放源代码 鼓励开发者创新
查看>>
《高并发Oracle数据库系统的架构与设计》一2.5 索引维护
查看>>
《Exchange Server 2010 SP1/SP2管理实践》——2.4 部署外部网络环境
查看>>
Firefox 是 Pwn2own 2014 上攻陷次数最多的浏览器
查看>>
阿里感悟(十八)- 应届生Review
查看>>
《计算广告:互联网商业变现的市场与技术》一第一部分 在线广告市场与背景...
查看>>
话说模式匹配(5) for表达式中的模式匹配
查看>>
《锋利的SQL(第2版)》——1.7 常用函数
查看>>